package org.springframework.aop.framework;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;
import java.util.List;

/**
 * @author zqc
 * @date 2022/12/16
 */
public class ReflectiveMethodInvocation implements MethodInvocation {

	protected final Object proxy;

	protected final Object target;

	protected final Method method;

	protected final Object[] arguments;

	protected final Class<?> targetClass;

	protected final List<Object> interceptorsAndDynamicMethodMatchers;

	private int currentInterceptorIndex = -1;

	public ReflectiveMethodInvocation(Object proxy,Object target, Method method, Object[] arguments,Class<?> targetClass,List<Object> chain) {
		this.proxy=proxy;
		this.target = target;
		this.method = method;
		this.arguments = arguments;
		this.targetClass=targetClass;
		this.interceptorsAndDynamicMethodMatchers=chain;
	}

	//5.最后一步！
	@Override
	public Object proceed() throws Throwable {
		//currentInterceptorIndex是当前的拦截器的下标，默认-1，我们先传过来after，再传来before
		// （但是执行的时候）会按照正常顺序，根据你的after还是before（这个又涉及一些源码了）

		// 初始currentInterceptorIndex为-1，每调用一次proceed就把currentInterceptorIndex+1
		//这里判断-1==2-1，等于就执行原生类方法（拦截器链里都执行完了），否则走下面
		//第二次来判断0==2-1
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			// 当调用次数 = 拦截器个数时
			// 触发当前method方法
			return method.invoke(this.target, this.arguments);
		}
		//这里得到连接器链里的拦截器，先得到。从0开始取，从小到大
		Object interceptorOrInterceptionAdvice =//注意这里先++，再取。-1->0，先取after
				this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);//先获得一个advisor
		// 取出普通拦截器，直接触发拦截器invoke方法，取出来after方法（应该后执行的），我们看他怎么处理
		return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
	}
	@Override
	public Method getMethod() {
		return method;
	}
	@Override
	public Object[] getArguments() {
		return arguments;
	}
	@Override
	public Object getThis() {
		return target;
	}
	@Override
	public AccessibleObject getStaticPart() {
		return method;
	}
}
